"use strict";

/**
 * ip
 * Created by liamjung on 2018/6/4.
 */
const serviceUtil = require("@libfintech/api-gateway-core/util/service_util");
const {ResponseError} = require("@libfintech/api-gateway-core/error/response_error");
const {matchConfig} = require("@libfintech/api-gateway-core/util/util");

/**
 * 检查名单
 * @param ip
 * @param list
 * @param isWhite
 * @param logger
 * @returns {boolean}   true表示包含，false表示不包含
 */
async function check(ip, list, isWhite, logger) {

    let flag = false;

    if (!list || list.length === 0) {
        //名单列表不存在时，忽略
        return isWhite;
    }

    let segments = ip.split(".");

    for (let ipTemplate of list) {

        if (ipTemplate.indexOf(".") === -1) {
            //表示serviceId
            ipTemplate = await serviceUtil.ip(ipTemplate);

            if (!ipTemplate) {
                //服务不存在时，忽略
                continue;
            }
        }

        let templateSegments = ipTemplate.split(".");

        for (let i = 0; i < templateSegments.length; i++) {

            //字符串转数字
            let seg = +segments[i];
            let tempSeg = templateSegments[i].trim();


            if (tempSeg === "*") {
                //通配
                flag = 0 <= seg && seg <= 255;
            } else if (tempSeg.indexOf("[") !== -1 && tempSeg.indexOf("]") !== -1) {
                //范围
                let arr = tempSeg.substring(1, tempSeg.length - 1).split(",");
                //字符串转数字
                let min = +arr[0].trim();
                let max = +arr[1].trim();

                flag = min <= seg && seg <= max;
            } else {
                //指定
                //字符串转数字
                tempSeg = +tempSeg;

                flag = seg === tempSeg;
            }

            if (!flag)
                break;
        }

        if (flag)
            break;
    }

    if (isWhite) {
        if (!flag)
            logger.warn("Current ip (value: " + ip + ") is not in the while list (value: " + list + ")");
    } else if (flag)
        logger.warn("Current ip (value: " + ip + ") is in the blacklist (value: " + list + ")");

    return flag;
}

async function main(pipeline, configs) {

    let req = pipeline.request;

    let config = matchConfig(req, configs);

    if (config) {

        let ip = pipeline.session.client.ip;

        //检查白名单
        if (await check(ip, config.whiteList, true, pipeline.logger) &&
            //检查黑名单
            !await check(ip, config.blackList, false, pipeline.logger)) {
            //白名单中存在，且黑名单中不存在时，忽略
        } else
            throw new ResponseError(403);
    } else {
        //ip配置不存在时，忽略
    }
}

module.exports = {
    main: main
};